package com.example.financechain.service.Impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.financechain.Utils.GatewayUtilss;
import com.example.financechain.Utils.JsonData;
import com.example.financechain.Utils.ResultCode;
import com.example.financechain.config.CacheKeyManager;
import com.example.financechain.domain.BlockInfomation;
import com.example.financechain.domain.DTO.DetailDTO;
import com.example.financechain.domain.entity.Blockexplore;
import com.example.financechain.domain.entity.Role;
import com.example.financechain.mapper.BlockexploreMapper;
import com.example.financechain.service.IBlockexploreService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.sdk.BlockInfo;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.json.Json;
import java.time.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yy
 * @since 2023-04-24
 */
@Slf4j
@Service
public class BlockexploreServiceImpl extends ServiceImpl<BlockexploreMapper, Blockexplore> implements IBlockexploreService {

    @Autowired
    GatewayUtilss gatewayUtilss;

    @Override
    public JsonData queryBlockdetail(DetailDTO detailDTO) {

        LambdaQueryWrapper<Blockexplore> lambdaQueryWrapper =new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(detailDTO.getTxid())){
            lambdaQueryWrapper.eq(Blockexplore::getTxid,detailDTO.getTxid());
            return JsonData.buildSuccess(getOne(lambdaQueryWrapper));
        }

        return JsonData.buildError("您输入的信息有误，不存在相关信息");

    }

    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Override
    public JsonData blocklist() {
//        String blockjson = stringRedisTemplate.opsForValue().get(CacheKeyManager.BLOCKINFO);
//
//        if (StringUtils.isNotBlank(blockjson)){
//            List<Blockexplore> blockexploreList = JSON.parseArray(blockjson,Blockexplore.class);
//            return JsonData.buildSuccess(blockexploreList);
//        }

        List<Blockexplore> blockexploreList = list();

        return JsonData.buildSuccess(blockexploreList);

    }

    @Async("taskExecutor")
    @Override
    public void queryBlock() {
        Role role =new Role();
        role.setRoleCertification("Org2MSP");
        role.setRoleName("武汉学院");

        try (Gateway gateway = gatewayUtilss.build(role).connect()) {
            Network network = gateway.getNetwork("energycarchannel");

            // Get the channel and query the blockchain for the block count and latest block
            Channel channel = network.getChannel();

            long blockCount = channel.queryBlockchainInfo().getHeight();

            //List<BlockInfomation> blockInfomationList =new ArrayList<>();
            List<Blockexplore> blockexploreList =new ArrayList<>();
            for (int i = 0; i < blockCount; i++) {

                Blockexplore blockexplore = getBlock(channel, i);

                //blockInfomationList.add(blockInfomation);
                blockexploreList.add(blockexplore);

            }

            stringRedisTemplate.opsForValue().set(CacheKeyManager.BLOCKINFO, JSON.toJSONString(blockexploreList),30L, TimeUnit.MINUTES);


        } catch (Exception e) {
            System.err.println("Failed to query blocklist: " + e);

        }

    }


    @Async("taskExecutor")
    @Override
    public void updateBlockstore() {
        List<Blockexplore> blockexploreList = list();

        int len = list().size();
        Role role =new Role();
        role.setRoleCertification("Org1MSP");
        role.setRoleName("武汉学院");

        try (Gateway gateway = gatewayUtilss.build(role).connect()) {
            Network network = gateway.getNetwork("energycarchannel");

            // Get the channel and query the blockchain for the block count and latest block
            Channel channel = network.getChannel();

            long blockCount = channel.queryBlockchainInfo().getHeight();
            //List<Blockexplore> blockexploreList2 =new ArrayList<>();
            for (int i = len; i < blockCount; i++) {

                Blockexplore blockexplore = getBlock(channel,i);

                save(blockexplore);

                //blockexploreList2.add(blockexplore);

            }

            //return blockexploreList;

        } catch (Exception e) {
            System.err.println("Failed to query blocklist: " + e);

        }

    }

    private Blockexplore getBlock(Channel channel , int i) throws Exception {


        BlockInfo blockInfo = channel.queryBlockByNumber(i);
        Iterable<BlockInfo.EnvelopeInfo> envelopeInfos = blockInfo.getEnvelopeInfos();
        String txid = null;
        for (BlockInfo.EnvelopeInfo envelopeInfo : envelopeInfos) {
            //资源消耗太大，后期关掉
            log.info("Transaction ID: " + envelopeInfo.getTransactionID());
            txid = envelopeInfo.getTransactionID();
        }
        Blockexplore blockexplore =new Blockexplore();
        blockexplore .setSysBlockId(blockInfo.getBlockNumber());//区块号
        blockexplore.setSysHash(Hex.encodeHexString(blockInfo.getDataHash()));//hash
        blockexplore.setSysPrehash(Hex.encodeHexString(blockInfo.getPreviousHash()));//前hash
        blockexplore.setTxid(txid);
        if (StringUtils.isNotBlank(txid)){
            HashMap<String, Object> hashMap = ResultCode.queryFromBlockByTxId(txid, channel);

            Date date = (Date)hashMap.get("blocktime");
            LocalDateTime blocktime = LocalDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);


            blockexplore.setBlocktime(blocktime);

            blockexplore.setIdentity((String) hashMap.get("identity"));
            List<String> blockinfolist= (List<String>) hashMap.get("blockInfo");
            if (blockinfolist.size()!=0){
                log.info("=========="+blockinfolist.toString()+"=======");
            }


            blockexplore.setBlockinfo(blockinfolist.toString());
        }
        return blockexplore;
    }



}
